package cn.tannn.cat.file.sdk.core.ftp;

import cn.tannn.cat.file.sdk.OssOperateAPI;
import cn.tannn.cat.file.sdk.api.UploadFile;
import cn.tannn.cat.file.sdk.bean.FileIndex;
import cn.tannn.cat.file.sdk.bean.FileStorage;
import cn.tannn.cat.file.sdk.config.FtpConfig;
import cn.tannn.cat.file.sdk.constants.OSSConstants;
import cn.tannn.cat.file.sdk.exception.FileException;
import cn.tannn.cat.file.sdk.utils.AboutFileUtil;
import cn.tannn.cat.file.sdk.utils.ResponseFile;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Objects;


/**
 * ftp
 *
 * @author <a href="https://t.tannn.cn/">tan</a>
 * @date 2024/6/12 下午1:17
 * @see <a href="https://developer.aliyun.com/article/319874">FTP的上传下载</a>
 */
@Service
@Slf4j
public class FtpOperate implements OssOperateAPI {

    /**
     * ftp 必须构建一个 ftpviews{@link OSSConstants#FTP_VIEWS_API_NAME} 接口实现预览功能
     * <p> 参考server中的 FileOperateController#ftpviews 接口
     *
     * @param upload  文件
     * @param storage 存储器
     * @return FileIndex
     * @throws IOException IOException
     */
    @Override
    public FileIndex uploadFile(UploadFile upload, FileStorage storage) throws IOException {
        FTPClient ftpClient = FtpUtils.createFtpClient(storage);
        try {
            FtpConfig ftpConfig = storage.getConfig().toJavaObject(FtpConfig.class);
            String originalName = upload.getFile().getOriginalFilename();
            if (originalName == null) {
                throw FileException.specialMessage("文件有问题，OriginalFilename 不允许为空");
            }
            // 新文件名
            String freshName;
            String suffixDot = AboutFileUtil.getFileSuffixDot(originalName);
            if (StringUtils.isNotBlank(upload.getFileName())) {
                freshName = upload.getFileName().trim() + suffixDot;
            } else {
                freshName = originalName;
            }
            String childFolder = Objects.isNull(upload.getChildFolder()) ? "" : upload.getChildFolder();
            String uploadDirStr = upload.getBucket() + OSSConstants.PATH_SEPARATOR + childFolder;
            String uploadDir = new String(uploadDirStr.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);

            String subPath = new String((childFolder + freshName).getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);


            String filePathStr = OSSConstants.PATH_SEPARATOR + uploadDir + freshName;
            String filePath = new String(filePathStr.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
            FtpUtils.createMultiLevelDirectory(ftpClient, uploadDir);
            // 二进制文件类型。
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            InputStream inputStream = upload.getFile().getInputStream();
            ftpClient.storeFile(filePath, inputStream);
            // 进入本地被动模式
            ftpClient.enterLocalPassiveMode();
            inputStream.close();
            ftpClient.logout();
            FileIndex fileStorage = new FileIndex();
            fileStorage.setStorageId(storage.getId());
            fileStorage.setStorage(storage.getStorage());
            fileStorage.setOriginalName(originalName);
            fileStorage.setFreshName(freshName);
            fileStorage.setSubPath(subPath);
            fileStorage.setPath(filePathStr);
            fileStorage.setUrl(ftpConfig.getBrowseUrl() + ftpConfig.getUsePrefix() + storage.getStorage() + "?filePath=" + filePathStr);
            fileStorage.setUrlSuffix(ftpConfig.getUsePrefix() + storage.getStorage() + "?filePath=" + filePathStr);
            fileStorage.setBucket(upload.getBucket());
            fileStorage.setBucketPath(filePathStr);
            fileStorage.setType(upload.getFile().getContentType());
            fileStorage.setSizeUnit(AboutFileUtil.getFileSizeUnit(upload.getFile().getSize()));
            fileStorage.setSize(upload.getFile().getSize());
            return fileStorage;
        } catch (Exception e) {
            throw e;
        } finally {
            FtpUtils.disConnection(ftpClient);
        }

    }


    @Override
    public boolean removeFile(FileIndex index) {
        FTPClient ftpClient = FtpUtils.createFtpClient(index.getStorageId());
        try {
            ftpClient.deleteFile(index.getPath());
            return true;
        } catch (Exception e) {
            log.error("ftp删除失败：index id : {} , URL: {}", index.getId(), index.getUrl(), e);
            throw FileException.specialMessage("文件删除失败");
        } finally {
            FtpUtils.disConnection(ftpClient);
        }
    }

    @Override
    public void downloadFile(HttpServletResponse response, FileIndex index) {
        FTPClient ftpClient = FtpUtils.createFtpClient(index.getStorageId());
        try {
            // remote:文件存储在FTP的位置
            String fileNameEncoding = new String(index.getPath().getBytes(StandardCharsets.UTF_8)
                    , StandardCharsets.ISO_8859_1);
            InputStream inputStream = ftpClient.retrieveFileStream(fileNameEncoding);

            HttpServletResponse downResponse = ResponseFile.customResponse(response
                    , index.getType(), index.getFreshName());
            //设置文件大小
            downResponse.setHeader("Content-Length", String.valueOf(index.getSize()));
            IOUtils.copy(inputStream, downResponse.getOutputStream());
        } catch (Exception e) {
            log.error("ftp文件下载失败：index id : {} , URL: {}", index.getId(), index.getUrl(), e);
        } finally {
            FtpUtils.disConnection(ftpClient);
        }
    }


}
